#ifndef __GZ_SERVICE_REGISTER_H__
#define __GZ_SERVICE_REGISTER_H__

#include "gazella_base.h"

#include "MicroProxyMessage.pb.h"

namespace Gazella {

class HttpClient;

#define LOAD_BALANCE_METHOD_MAP(XX) \
    XX(0, METHOD_RANDOM,   LOAD_BALANCE_METHOD_RANDOM)  \
    XX(1, METHOD_POLLING,  LOAD_BALANCE_METHOD_POLLING) \
    XX(2, METHOD_SEQUENCE, LOAD_BALANCE_METHOD_SEQUENCE) \
    XX(3, METHOD_MAX,      LOAD_BALANCE_METHOD_MAX)     \

enum LoadBalanceMethodEnum {
#define XX(num, name, string) LOAD_BALANCE_##name = num,
    LOAD_BALANCE_METHOD_MAP(XX)
#undef XX
};

class ServiceRegister: public GazellaBase {
private:
    ServiceRegister();
    ~ServiceRegister();

public:
    ///////////////////////////for user///////////////////////////////////
    //lazy initialization 
    static ServiceRegister* get_instance(); 

    const std::string uuid();

    //set the service name, same as ros node name, one process only have one service register instance
    void set_service_name(const std::string& service_name); 
    const std::string service_name();

    //set the service nickname
    void set_service_nickname(const std::string& service_nickname);
    const std::string service_nickname();

    //set the global domain id (not effective now)
    void set_global_domain_id(uint32_t domain_id);
    const uint32_t global_domain_id();

    //set the http server port (41001);
    //dont't modify unless necessary
    void set_http_server_port(int port);
    const int http_server_port();

    //set the websocket server port (41002), 
    //dont't modify unless necessary
    void set_websocket_server_port(int port);
    const int websocket_server_port();

    //set the loadbalance method, default is random
    void set_loadbalance_method(LoadBalanceMethodEnum method);
    const LoadBalanceMethodEnum loadbalance_method();

    //set the service sequence
    void set_service_sequence(uint32_t order);
    const uint32_t service_sequence();

    //set the service center id
    void set_service_center_id(uint32_t center_id);
    const uint32_t service_center_id();

    ///////////////////////////for framework///////////////////////////////////
    //register to microproxy
    void register_to_microproxy();
    void async_register_to_microproxy();

    //add a server interface (for service, param, action, stream)
    int add_interface(
        const std::string& if_name, //server interface name
        MicroProxyMessage::ServiceTypeEnum service_type, //server type
        uint32_t domain_id = 0,  //domain id, default 0
        const std::string& describe = "" //server interface describe
    );

    //add a server interface (for topic subscribe only)
    int add_interface(
        const std::string& topic, //topic name to subscribe
        MicroProxyMessage::ServiceTopicMethodEnum method, //always SUB
        uint32_t qos = 0, //qos, default 0
        uint32_t domain_id = 0,  //domain id, default 0
        const std::string& describe = "" //topic subscribe describe
    );

    //delete a server interface (service, param, action, stream)
    int del_interface(const std::string& if_name, MicroProxyMessage::ServiceTypeEnum service_type);

    //delete a topic subscribe
    int del_interface(const std::string& topic, MicroProxyMessage::ServiceTopicMethodEnum method);

    void del_all_interface();

private:
    std::mutex m_lock;

    MicroProxyMessage::ServiceRegister m_service_register;
    std::shared_ptr<HttpClient> m_httpclient;
    ev::timer m_heartbeat_timer;

    //async
    ev::async m_async_watcher;

    uint32_t m_version;

private:
    void __on_heartbeat(ev::timer &w, int revents);

    void __async_register_to_microproxy_callback(ev::async &w, int revents);
};
} //namespace Gazella

#endif